from detect.color import detect_color
from os import path
from sys import argv
from json import load, dump
from PyQt5.QtWidgets import QApplication, QColorDialog, QMainWindow, QFileDialog, QMessageBox, QProgressBar
from PyQt5.QtCore import QObject, QThread, QUrl, pyqtSignal
from PyQt5.QtMultimedia import QMediaPlayer, QMediaContent
from Gui.Ui_MainWindow import Ui_MainWindow
#from Gui.main_window import MainWindow
from codec.Media import Media


class DetectWorker(QThread):
    '''Worker thread to detect marks in videos.

    ## Attributes:

    media: Media

    isCanceled: bool
        If this is set to `True`, the worker thread finishes.

    progressBar: QProgressBar
        A progress bar set to reflect the processing progress.
    '''

    def __init__(self, media: Media, progressBar: QProgressBar, pg: QObject):
        super().__init__()
        self.media = media
        self.isCanceled = False
        self.progressBar = progressBar
        self.progressChanged = pg.progressChanged

    def run(self):
        # try:
        #     with open('./save.json') as file:
        #         data = load(file)
        #     if self.media.filepath == data['filepath'] and self.media.method == data['method']:
        #         self.media.clips = data['clips']
        #         return
        # except:
        #     pass
        for i in self.media.detect():
            if self.isCanceled:
                break
            # self.progressBar.setValue(i)
            self.progressChanged.emit(i)
        with open('./save.json', 'w') as file:
            dump(
                {
                    'filepath': self.media.filepath,
                    'method': self.media.method,
                    'clips': self.media.getClips()
                },
                file
            )


class ExportWorker(QThread):
    def __init__(self, media: Media, path: str, inOne: bool):
        super().__init__()
        self.media = media
        self.path = path
        self.inOne = inOne

    def run(self):
        self.media.export(
            self.path,
            self.inOne
        )


class Gui(Ui_MainWindow):
    def __init__(self, MainWindow: QMainWindow):
        super().__init__()

        self.setupUi(MainWindow)
        self.MainWindow: QMainWindow = MainWindow

        self.cancelBtn.clicked.connect(self.cancelBtnOnClick)

        self.exportBtn.clicked.connect(self.exportBtnOnClick)

        self.importExploreBtn.clicked.connect(self.importExploreBtnOnClick)

        self.startBtn.clicked.connect(self.startBtnOnClick)

        self.exportExploreBtn.clicked.connect(self.exportExploreBtnOnClick)

        self.playBtn.clicked.connect(self.playBtnOnClick)

        self.player = QMediaPlayer()
        self.player.setVideoOutput(self.playerWidget)
        self.player.setNotifyInterval(1)
        self.player.positionChanged.connect(self.PlayerPositionOnChange)

        self.horizontalSlider.sliderMoved.connect(
            lambda value: self.player.setPosition(value)
        )

        self.clipComboBox.currentIndexChanged.connect(
            self.clipComboBoxCurrentIndexOnChange)

        self.fromSlider.setEnabled(False)
        self.toSlider.setEnabled(False)
        self.fromSlider.sliderMoved.connect(self.fromSliderOnMove)
        self.toSlider.sliderMoved.connect(self.toSliderOnMove)

        self.methodComboBox.currentIndexChanged.connect(
            self.methodComboBoxCurrentIndexOnChange)

        self.goodClrBtn.clicked.connect(self.goodClrBtnOnClick)
        self.badClrBtn.clicked.connect(self.badClrBtnOnClick)

        self.goodRSpinBox.valueChanged.connect(self.goodSpinBoxOnChange)
        self.goodGSpinBox.valueChanged.connect(self.goodSpinBoxOnChange)
        self.goodBSpinBox.valueChanged.connect(self.goodSpinBoxOnChange)
        self.badRSpinBox.valueChanged.connect(self.badSpinBoxOnChange)
        self.badGSpinBox.valueChanged.connect(self.badSpinBoxOnChange)
        self.badBSpinBox.valueChanged.connect(self.badSpinBoxOnChange)

        # Signals
        class ProgressChangeEmitter(QObject):
            progressChanged = pyqtSignal([int])
        self.progressChangeEmitter = ProgressChangeEmitter()
        self.progressChangeEmitter.progressChanged.connect(
            self.progressOnChange)

    def progressOnChange(self, value):
        self.progressBar.setValue(value)

    def goodSpinBoxOnChange(self):
        self.goodClrDisp.setStyleSheet(
            f'background:rgb({self.goodRSpinBox.value()},{self.goodGSpinBox.value()},{self.goodBSpinBox.value()})')

    def badSpinBoxOnChange(self):
        self.badClrDisp.setStyleSheet(
            f'background:rgb({self.badRSpinBox.value()},{self.badGSpinBox.value()},{self.badBSpinBox.value()})')

    def goodClrBtnOnClick(self):
        clr = QColorDialog.getColor()
        self.goodRSpinBox.setValue(clr.red())
        self.goodGSpinBox.setValue(clr.green())
        self.goodBSpinBox.setValue(clr.blue())

    def badClrBtnOnClick(self):
        clr = QColorDialog.getColor()
        self.badRSpinBox.setValue(clr.red())
        self.badGSpinBox.setValue(clr.green())
        self.badBSpinBox.setValue(clr.blue())

    def methodComboBoxCurrentIndexOnChange(self, value):
        if value == 0:
            self.goodModGroup.show()
            self.badModGroup.show()
        else:
            self.goodModGroup.hide()
            self.badModGroup.hide()

    def fromSliderOnMove(self, value):
        if value + self.toSlider.value() >= self.player.duration():
            self.toSlider.setValue(self.player.duration() - value)
            self.media.clips[self.clipComboBox.currentIndex() -
                             1]['end'] = value / 1000
            self.horizontalSlider.setMaximum(value)
        self.media.clips[self.clipComboBox.currentIndex() -
                         1]['start'] = value / 1000
        self.horizontalSlider.setMinimum(value)

    def toSliderOnMove(self, value):
        if value + self.fromSlider.value() >= self.player.duration():
            self.fromSlider.setValue(self.player.duration() - value)
            self.media.clips[self.clipComboBox.currentIndex(
            ) - 1]['start'] = (self.player.duration() - value) / 1000
            self.horizontalSlider.setMinimum(self.player.duration() - value)
        self.media.clips[self.clipComboBox.currentIndex(
        ) - 1]['end'] = (self.player.duration() - value) / 1000
        self.horizontalSlider.setMaximum(self.player.duration() - value - 10)

    def clipComboBoxCurrentIndexOnChange(self, index: int):
        self.player.pause()
        if index == 0:
            self.horizontalSlider.setRange(0, self.player.duration() - 10)
            self.player.setPosition(0)
            self.fromSlider.setValue(0)
            self.toSlider.setValue(0)
            self.fromSlider.setEnabled(False)
            self.toSlider.setEnabled(False)
        else:
            clip = self.media.getClips()[index - 1]
            start = int(clip['start'] * 1000)
            end = int(min(clip['end'] * 1000, self.player.duration() - 10))
            self.horizontalSlider.setRange(
                start, end)
            self.player.setPosition(start)
            self.fromSlider.setValue(start)
            self.toSlider.setValue(self.player.duration() - end - 1)
            self.fromSlider.setEnabled(True)
            self.toSlider.setEnabled(True)

    def PlayerPositionOnChange(self, value):
        if value >= self.horizontalSlider.maximum() and self.player.state() == QMediaPlayer.State.PlayingState:
            self.player.pause()
        elif value < self.horizontalSlider.minimum():
            self.player.setPosition(self.horizontalSlider.minimum())
        else:
            self.horizontalSlider.setValue(value)

    def importExploreBtnOnClick(self):
        filepath = QFileDialog.getOpenFileName(
            parent=self.MainWindow,
            caption='Select a Video...',
            filter='Video File (*.mp4)'
        )[0]
        self.filepathLine.setText(filepath)

    def startBtnOnClick(self):
        if self.filepathLine.text() == '':
            QMessageBox.information(
                self.MainWindow,
                'File not selected',
                'Please select a video file to proceed.'
            )
        else:
            self.media: Media = Media(
                filepath=self.filepathLine.text(),
                method=self.methodComboBox.currentText()
            )
            self.media.goodRGB = (
                self.goodRSpinBox.value(),
                self.goodGSpinBox.value(),
                self.goodBSpinBox.value(),
            )
            self.media.badRGB = (
                self.badRSpinBox.value(),
                self.badGSpinBox.value(),
                self.badBSpinBox.value(),
            )
            self.startBtn.setEnabled(False)
            self.cancelBtn.setEnabled(True)
            self.progressBar.setEnabled(True)
            self.detectWorker = DetectWorker(
                self.media, self.progressBar, self.progressChangeEmitter)

            def detectOnFinish():
                self.cancelBtn.setEnabled(False)
                self.startBtn.setEnabled(True)
                self.exportBtn.setEnabled(True)
                self.playBtn.setEnabled(True)
                self.progressBar.setEnabled(False)

                if self.detectWorker.isCanceled:
                    self.progressBar.setValue(0)
                else:
                    self.progressBar.setValue(100)
                    cntClip = len(self.media.getClips())
                    self.clipComboBox.clear()
                    self.clipComboBox.addItem('full')
                    for i in range(1, 1 + cntClip):
                        self.clipComboBox.addItem(f'{i}')
                    self.player.setMedia(
                        QMediaContent(QUrl.fromLocalFile(self.filepathLine.text())))

                    def playerOnSetUp():
                        self.horizontalSlider.setRange(
                            0, self.player.duration() - 10)
                        self.fromSlider.setRange(
                            0, self.player.duration() - 10)
                        self.toSlider.setRange(0, self.player.duration() - 10)
                        #self.media.clips[-1]['end'] = self.player.duration() / \1000
                        self.player.durationChanged.disconnect(playerOnSetUp)

                    self.player.durationChanged.connect(playerOnSetUp)
                    self.playBtn.setEnabled(True)

            self.detectWorker.finished.connect(detectOnFinish)
            self.detectWorker.start()

    def cancelBtnOnClick(self):
        self.detectWorker.isCanceled = True

    def exportExploreBtnOnClick(self):
        filepath = QFileDialog.getExistingDirectory(
            parent=self.MainWindow,
            caption='Select a Video...'
        )
        self.outputLine.setText(filepath)

    def exportBtnOnClick(self):
        self.exportWorker = ExportWorker(
            self.media,
            self.outputLine.text(),
            self.mergeCheckBox.isChecked()
        )
        self.exportWorker.start()

    def playBtnOnClick(self):
        if self.player.state() == QMediaPlayer.State.PlayingState:
            self.player.pause()
        elif self.horizontalSlider.value() == self.horizontalSlider.maximum():
            self.player.setPosition(self.horizontalSlider.minimum())
            self.player.play()
        else:
            self.player.play()

    def show(self):
        self.MainWindow.show()


def main():
    app = QApplication(argv)
    gui = Gui(QMainWindow())
    gui.show()
    app.exec()
